<?php

//+----------------------------------------------------------------------
//| ThinkPHP [ WE CAN DO IT JUST THINK IT ]
//+----------------------------------------------------------------------
//| Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
//+----------------------------------------------------------------------
//| Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
//+----------------------------------------------------------------------
//| Author: liu21st <liu21st@gmail.com>
//+----------------------------------------------------------------------
//$Id: common.php 2799 2012-03-05 07:18:06Z liu21st $
/**
  +------------------------------------------------------------------------------
 * Think 基础函数库
  +------------------------------------------------------------------------------
 * @category   Think
 * @package  Common
 * @author   liu21st <liu21st@gmail.com>
 * @version  $Id: common.php 2799 2012-03-05 07:18:06Z liu21st $
 * @last modify 2012-11-30 16:53:36 by 2012-11-26 13:53:15
  +------------------------------------------------------------------------------

 */

/**
 * 实例化模块Action 格式：[项目://][分组/]模块
 *
 * @last modify 2012-11-30 16:54:46 by mashanling
 *
 * @param string $name 模块名称
 *
 * @return mixed 如果模块存在，返回模块实例，否则返回false
 */
function A($name) {
    static $_action = array();

    if (strpos($name, '://')) { //指定项目
        $name = str_replace('://', '/Action/', $name);
    }
    else {
        $name = '@/Action/' . $name;
    }

    if (isset($_action[$name])) {
        return $_action[$name];
    }

    import($v = $name . 'Action');

    $class = basename($v);

    if (class_exists($class, false)) {
        $action = new $class();
        $_action[$name] = $action;

        return $action;
    }

    return false;
}//end A

/**
 * 动态添加行为扩展到某个标签
 *
 * @last modify 2012-11-30 17:11:19 by mashanling
 *
 * @param string $tag      标签名
 * @param string $behavior 行为
 * @param string $path     行为文件
 *
 * @return void 无返回值
 */
function add_tag_behavior($tag, $behavior, $path = '') {
    $array = C($v = 'tags.' . $tag);

    !$array && $array = array();

    if ($path) {
        $array[$behavior] = $path;
    }
    else {
        $array[] = $behavior;
    }

    C($v, $array);
}

/**
 * 快速定义和导入别名
 *
 * @last modify 2012-11-30 17:21:28 by mashanling
 *
 * @param mixed  $alias     别名，字符串或数组
 * @param string $classfile 对应文件
 *
 * @return bool
 */
function alias_import($alias, $classfile = '') {
    static $_alias = array();

    if (is_string($alias)) {

        if (isset($_alias[$alias])) {//导入
            return require_cache($_alias[$alias]);
        }
        elseif ('' !== $classfile) {//定义别名导入
            $_alias[$alias] = $classfile;
        }
    }
    elseif (is_array($alias)) {
        $_alias = array_merge($_alias, $alias);
    }

    return false;
}

/**
 * 批量定义常量
 *
 * @last modify 2012-12-01 15:35:55 by mashanling
 *
 * @param array $array $k => $v常量数组
 * @param bool  $check 是否需要defined($v)判断
 *
 * @return string php定义常量代码
 */
function array_define($array, $check = true) {
    $content = "\n";

    foreach ($array as $key => $val) {
        $key = strtoupper($key);

        if ($check) {
            $content .= "defined('{$key}') or ";
        }

        if (is_int($val) || is_float($val)) {
            $content .= "define('{$key}', {$val});";
        }
        elseif (is_bool($val)) {
            $val = $val ? 'true' : 'false';
            $content .= "define('{$key}', {$val});";
        }
        elseif (is_string($val)) {
            $content .= "define('{$key}', '" . addslashes($val) . "');";
        }

        $content .= "\n";
    }

    return $content;
}

/**
 * 执行行为
 *
 * @last modify 2012-11-30 17:26:32 by mashanling
 *
 * @param string $name   行为名称
 * @param array  $params 参数
 *
 * @return void 无返回值
 */
function B($name, &$params = null) {
    $class = $name . 'Behavior';
    G('behaviorStart');
    $behavior = new $class();
    $behavior->run($params);

    if (APP_DEBUG) {//记录行为的执行日志
        G('behaviorEnd');
        C('LOG_LEVEL', E_APP_DEBUG);
        trigger_error('Run ' . $name . ' Behavior [ RunTime:' . G('behaviorStart', 'behaviorEnd', 6) . 's ]');
    }
}

/**
 * 获取或设置配置值
 *
 * @last modify 2012-11-30 17:34:36 by mashanling
 *
 * @param mixed $name  配置名或配置数组
 * @param mixed $value 配置值
 *
 * @return mixed
 */
function C($name = null, $value = null) {
    static $_config = array();

    if (empty($name)) {//无参数时获取所有
        return $_config;
    }

    if (is_string($name)) {//优先执行设置获取或赋值

        if (!strpos($name, '.')) {
            $name = strtolower($name);

            if (null === $value) {
                return isset($_config[$name]) ? $_config[$name] : null;
            }

            $_config[$name] = $value;

            return;
        }

        //二维数组设置和获取支持
        $name    = explode('.', $name);
        $name[0] = strtolower($name[0]);

        if (null === $value) {
            return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null;
        }

        $_config[$name[0]][$name[1]] = $value;

        return;
    }

    if (is_array($name)) {//批量设置
        return $_config = array_merge($_config, array_change_key_case($name));
    }

    return null;
}//end C

/**
 * 编译文件
 *
 * @last modify 2012-12-01 15:31:35 by mashanling
 *
 * @param string $filename 待编译文件
 *
 * @return mixed
 */
function compile($filename) {
    $content = file_get_contents($filename);
    $content = substr(trim($content), 5);

    if (strpos($content, '?>') && '?>' == substr($content, - 2)) {//干掉php结束符
        $content = substr($content, 0, -2);
    }

    return $content;
}

/**
 * 实例化模型Model 格式 项目://分组/模块
 *
 * @last modify 2012-11-30 17:38:12 by mashanling
 *
 * @param string $name 模型名称
 *
 * @return resource 模型实例
 */
function D($name = '') {

    if (empty($name)) {
        return new Model();
    }

    static $_model = array();

    if (strpos($name, '://')) { //指定项目
        $name = str_replace('://', '/Model/', $name);
    }
    else {
        $name = C('DEFAULT_APP') . '/Model/' . $name;
    }

    if (isset($_model[$name])) {
        return $_model[$name];
    }

    import($v = $name . 'Model');

    $class = basename($v);

    if (class_exists($class)) {
        $model = new $class();
    }
    else {
        $model = new Model(basename($name));
    }

    $_model[$name] = $model;

    return $model;
}//end D

/**
 * 区分大小写的文件存在判断
 *
 * @last modify 2012-11-30 17:47:31 by mashanling
 *
 * @param string $filename 文件
 *
 * @return bool 文件存在，返回true，否则返回false
 */
function file_exists_case($filename) {

    if (is_file($filename)) {

        if (IS_WIN && C('APP_FILE_CASE') && basename(realpath($filename)) != basename($filename)) {
            return false;
        }

        return true;
    }

    return false;
}

/**
 * 过滤器方法
 *
 * @last modify 2012-11-30 17:48:58 by mashanling
 *
 * @param string $name    过滤器名称
 * @param string $content 过滤内容
 *
 * @return string 过滤后内容
 */
function filter($name, &$content) {
    $class = $name . 'Filter';
    require_cache(LIB_PATH . 'Filter/' . $class . '.class.php');
    $filter  = new $class();
    $content = $filter->run($content);
}

/**
 * 记录和统计时间（微秒）
 *
 * @last modify 2012-11-30 17:50:49 by mashanling
 *
 * @param string $start 开始标识符
 * @param mixed  $end   结束标识符或结束时间
 * @param int    $dec   小数点精度，默认：4
 *
 * @return void 无返回值
 */
function G($start, $end = '', $dec = 4) {
    static $_info = array();

    if (is_float($end)) {//记录时间
        $_info[$start] = $end;
    }
    elseif (!empty($end)) {//统计时间

        if (!isset($_info[$end])) {
            $_info[$end] = microtime(true);
        }

        return number_format(($_info[$end] - $_info[$start]), $dec);
    }
    else {//记录时间
        $_info[$start] = microtime(true);
    }
}

/**
 * 导入所需的类库 同java的Import，本函数有缓存功能
 *
 * @last modify 2012-11-30 17:50:49 by mashanling
 *
 * @param string $class    类库命名空间字符串
 * @param string $base_url 起始路径
 * @param string $ext      导入的文件扩展名，默认.class.php
 *
 * @return bool
 */
function import($class, $base_url = '', $ext = '.class.php') {
    static $_file = array();

    $class = str_replace(array('.', '#'), array('/', '.'), $class);

    if ('' === $base_url && false === strpos($class, '/')) {//检查别名导入
        return alias_import($class);
    }

    if (isset($_file[$v = $class . $base_url])) {
        return true;
    }
    else {
        $_file[$v] = true;
    }

    $class_path = explode('/', $class);

    if (empty($base_url)) {
        $first_part = $class_path[0];
        $basename   = basename(LIB_PATH);

        //加载当前项目应用类库Admin/Action/AdminAction,Admin/Model/AdminModel
        if ('@' == $first_part || APP_NAME == $first_part) {
            $base_url = dirname(LIB_PATH);
            //Admin/Model/AdminModel => dirname(LIB_PATH) . '/Model/AdminModel'
            $class   = substr_replace($class, $basename . '/', 0, strlen($first_part) + 1);
        }
        elseif ('web' == strtolower($first_part)) {//by mashanling on 2012-11-26 15:19:31
            $base_url = APP_PATH . 'App/Web/' . $basename;
            $class   = substr($class, 4);
        }
        elseif ('think' == strtolower($first_part)) { //think 官方基类库
            $base_url = CORE_PATH;
            $class    = substr($class, 6);
        }
        elseif (in_array(strtolower($first_part), array('org', 'com'))) {//org 第三方公共类库 com 企业公共类库
            $base_url = LIBRARY_PATH;
        }
        else {//加载其他项目应用类库
            $class    = substr_replace($class, '', 0, strlen($first_part) + 1);
            $base_url = APP_PATH . "../{$first_part}/{$basename}/";
        }
    }

    $base_url .= '/' == substr($base_url, - 1) ? '' : '/';

    $classfile  = $base_url . $class . $ext;

    if (!class_exists(basename($class), false)) {//如果类不存在 则导入类库文件
        return require_cache($classfile);
    }
}//end import

/**
 * 获取和设置语言定义(不区分大小写)
 *
 * @last modify 2012-11-30 18:05:01 by mashanling
 *
 * @param mixed $name  语言名称或语言数组
 * @param mixed $value 语言值
 *
 * @return mixed
 */
function L($name = null, $value = null) {
    static $_lang = array();

    if (empty($name)) {//空参数返回所有定义
        return $_lang;
    }

    //判断语言获取(或设置),若不存在,直接返回全大写$name
    if (is_string($name)) {
        $copy = $name;
        $name = strtoupper($name);

        if (is_null($value)) {

            if (!isset($_lang[$name]) && false !== strpos($name, ',')) {//批量
                $msg = '';

                foreach (explode(',', $copy) as $v) {

                    if (0 === strpos($v, '%')) {//第一个为%，原形返回
                        $msg .= substr($v, 1);
                    }
                    else {
                        $msg .= L($v);
                    }
                }

                $_lang[$name] = $msg; //语言定义

                return $msg;
            }

            return isset($_lang[$name]) ? $_lang[$name] : $name;
        }

        $_lang[$name] = $value; //语言定义

        return;
    }

    if (is_array($name)) {//批量定义
        $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER));
    }

    return;
}//end L

/**
 * 基于命名空间方式导入函数库load('@.Util.Array')
 *
 * @last modify 2012-11-30 18:08:36 by mashanling
 *
 * @param string $name     函数库命名空间字符串
 * @param string $base_url 起始路径
 * @param string $ext      导入的文件扩展名，默认.php
 *
 * @return void 无返回值
 */
function load($name, $base_url = '', $ext = '.php') {
    $name = str_replace(array('.', '#'), array('/', '.'), $name);

    if (empty($base_url)) {

        if (0 === strpos($name, '@/')) {//加载当前项目函数库
            $base_url = COMMON_PATH;
            $name     = substr($name, 2);
        }
        else {//加载ThinkPHP 系统函数库
            $base_url = EXTEND_PATH . 'Function/';
        }
    }

    $base_url .= '/' == substr($base_url, - 1) ? '' : '/';

    require_cache($base_url . $name . $ext);
}

/**
 * 实例化一个没有模型文件的Model
 *
 * @last modify 2012-11-30 18:10:29 by mashanling
 *
 *  @param string $name         Model名称 支持指定基础模型 例如 MongoModel:User
 * @param string  $table_prefix 表前缀
 * @param mixed   $connection   数据库连接信息
 *
 * @return resource 模型实例
 */
function M($name = '', $table_prefix = '', $connection = '') {
    static $_model = array();

    if (strpos($name, ':')) {
        list($class, $name) = explode(':', $name);
    }
    else {
        $class = 'Model';
    }

    if (!isset($_model[$v = $name . '_' . $class])) {
        $_model[$v] = new $class($name, $table_prefix, $connection);
    }

    return $_model[$v];
}

/**
 * 循环创建目录
 *
 * @last modify 2012-11-30 18:12:56 by mashanling
 *
 * @param string $dir  路径
 * @param int    $mode 权限，默认0755
 *
 * @return bool 创建成功，返回true，否则返回false
 */
function mk_dir($dir, $mode = 0755) {
    return mkdir($dir, $mode, true);
}

/**
 * 设置和获取统计数据
 *
 * @last modify 2012-11-30 18:12:56 by mashanling
 *
 * @param string $key  键值
 * @param int    $step 步长，默认0，表示取值
 *
 * @return mixed
 */
function N($key, $step = 0) {
    static $_num = array();

    if (!isset($_num[$key])) {
        $_num[$key] = 0;
    }

    if (empty($step)) {
        return $_num[$key];
    }
    else {
        $_num[$key] = $_num[$key] + $step;
    }
}

/**
 * 字符串命名风格转换
 *
 * @last modify 2012-12-01 13:23:53 by mashanling
 *
 * @param string $name 待转换字符串
 * @param int    $type 转换格式，0 => user_action => userAction, 1=> UserAction => user_action
 *
 * @return string 转换后字符串
 */
function parse_name($name, $type = 0) {

    if ($type) {//user_action => userAction
        return ucfirst(preg_replace('/_([a-zA-Z])/e', "strtoupper('\\1')", $name));
    }
    else {//UserAction => user_action
        return strtolower(trim(preg_replace('/[A-Z]/', '_\\0', $name), '_'));
    }
}

/**
 * 跨模块调用操作方式 [项目://][分组/]模块/操作
 *
 * @last modify 2012-12-01 13:27:16 by mashanling
 *
 * @param string $url   操作字符串
 * @param array   $vars 传递参数
 *
 * @return mixed 模块存在，返回模块操作方法结果，否则返回false
 */
function R($url, $vars = array()) {
    $info   = pathinfo($url);//Admin/add
    $action = $info['basename'];
    $module = $info['dirname'];
    $class  = A($module);

    return $class ? call_user_func_array(array(&$class, $action), $vars) : false;
}

/**
 * 优化的require_once
 *
 * @last modify 2012-12-01 13:36:47 by mashanling
 *
 * @param string $filename 包含文件
 *
 * @return bool 成功包含，返回true，否则返回false
 */
function require_cache($filename) {
    static $_inport_files = array();

    if (!isset($_inport_files[$filename])) {

        if (file_exists_case($filename)) {
            require($filename);
            $_inport_files[$filename] = true;
        }
        else {
            $_inport_files[$filename] = false;
        }
    }

    return $_inport_files[$filename];
}

/**
 * 去除代码中的空白和注释
 *
 * @last modify 2012-12-01 13:38:18 by mashanling
 *
 * @param string $content 代码
 *
 * @return string 去除代码中的空白和注释的代码
 */
function strip_whitespace($content) {
    $strip_str   = '';
    $tokens     = token_get_all($content);//分析php源码
    $last_space = false;

    unset($content);

    for ($i = 0, $j = count($tokens); $i < $j; $i++) {

        if (is_string($v = $tokens[$i])) {
            $last_space = false;
            $strip_str .= $v;
        }
        else {
            switch ($v[0]) {

                case T_COMMENT://过滤各种PHP注释
                case T_DOC_COMMENT:
                    break;

                case T_WHITESPACE://过滤空格

                    if (!$last_space) {
                        $strip_str .= ' ';
                        $last_space = true;
                    }

                    break;

                case T_START_HEREDOC:
                    $strip_str .= "<<<THINK\n";
                    break;

                case T_END_HEREDOC:
                    $strip_str .= "THINK;\n";

                    for ($k = $i + 1; $k < $j; $k++) {

                        if (is_string($vv = $tokens[$k]) && ';' == $vv) {
                            $i = $k;
                            break;
                        }
                        elseif (T_CLOSE_TAG == $vv[0]) {
                            break;
                        }
                    }

                    break;

                default :
                    $last_space = false;
                    $strip_str .= $v[1];
            }
        }
    }

    unset($tokens);

    return $strip_str;
}//end strip_whitespace;

/**
 * 处理标签扩展
 *
 * @last modify 2012-12-01 15:20:47 by mashanling
 *
 * @param string $name   行为名称
 * @param array  $params 参数
 *
 * @return mixed
 */
function tag($tag, &$params = null) {
    $extends = C('extends.' . $tag);//系统标签扩展
    $tags    = C('tags.' . $tag);//应用标签扩展

    if (!empty($tags)) {

        if (empty($tags['_overlay']) && !empty($extends)) { //合并扩展
            $tags = array_unique(array_merge($extends, $tags));
        }
        elseif (isset($tags['_overlay'])) { //通过设置 '_overlay'=>1 覆盖系统标签
            unset($tags['_overlay']);
        }
    }
    elseif (!empty($extends)) {
        $tags = $extends;
    }

    if ($tags) {

        if (APP_DEBUG) {
            G($tag . 'Start');
            C('LOG_LEVEL', E_APP_DEBUG);
            trigger_error('Tag[ ' . $tag . ' ] --START--');
        }

        foreach ($tags as $key => $name) {//执行扩展

            if (!is_int($key)) { //指定行为类的完整路径 用于模式扩展
                $name = $key;
            }

            B($name, $params);
        }

        if (APP_DEBUG) { //记录行为的执行日志
            C('LOG_LEVEL', E_APP_DEBUG);
            trigger_error('Tag[ ' . $tag . ' ] --END-- [ RunTime:' . G($tag . 'Start', $tag . 'End', 6) . 's ]');
        }
    }
    else {//未执行任何行为 返回false
        return false;
    }
}//end tag

/**
 * 快速导入第三方框架类库
 * 所有第三方框架的类库文件统一放到 系统的Vendor目录下面
 * 并且默认都是以.php后缀导入
 *
 * @last modify 2012-12-01 15:27:58 by mashanling
 *
 * @param string $class    类文件名
 * @param string $base_url 起始路径
 * @param string $ext      导入的文件扩展名，默认.php
 *
 * @return mixed
 */
function vendor($class, $base_url = '', $ext = '.php') {

    if (empty($base_url)) {
        $base_url = VENDOR_PATH;
    }

    return import($class, $base_url, $ext);
}

/**
 * 渲染输出Widget
 *
 * @last modify 2012-12-01 15:29:33 by mashanling
 *
 * @param string $name    名称
 * @param array  $data    数据
 * @param bool   $return  是否返回内容
 *
 * @return mixed
 */
function W($name, $data = array(), $return = false) {
    $class = $name . 'Widget';

    require_cache(LIB_PATH . 'Widget/' . $class . '.class.php');

    if (!class_exists($class)) {
        throw new Exception(L('_CLASS_NOT_EXIST_') . ':' . $class);
    }

    $widget  = Think::instance($class);
    $content = $widget->render($data);

    if ($return) {
        return $content;
    }

    echo $content;
}